﻿using Infrastructure;
using Infrastructure.Attribute;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using ZR.DataCollection.Execute;
using ZR.DataCollection.Helper;
using ZR.DataCollection.ICommunication;
using ZR.DataCollection.InterfaceClass;
using ZR.DataCollection.Model;
using ZR.DataCollection.SingleParameter;
using ZR.Model.Models.ProductionControl;
using ZR.Service.IService.ProductionControl;
using ZR.ServiceCore.Signalr;

namespace ZR.DataCollection.Communication
{
    [AppService(ServiceType = typeof(ICommManage), ServiceLifetime = LifeTime.Singleton)]
    public class CommManage : ICommManage
    {
        private System.Timers.Timer watchDogTimer = null;
        private readonly IServerConfigService _serverConfigService;
        private readonly IWorkstationConfigService _workstationConfigService;
        private readonly IScannerConfigService _scannerConfigService;
        private readonly IPlcConfigService _plcConfigService;
        private readonly ICommunicationConfigService _commAddressService;
        private readonly IEnumerable<IExecuteWork> _executeWorks;
        private readonly ILogger<CommManage> _logger;
        private readonly IHubContext<MessageHub> _hubContext;

        public CommManage(
            IEnumerable<IExecuteWork> executeWorks,
            IServerConfigService serverConfigService,
            IWorkstationConfigService workstationConfigService,
            IScannerConfigService scannerConfigService,
            IPlcConfigService plcConfigService,
            ICommunicationConfigService commAddressService,
            ILogger<CommManage> logger,
            IHubContext<MessageHub> hubContext)
        {
            _executeWorks = executeWorks;
            _serverConfigService = serverConfigService;
            _workstationConfigService = workstationConfigService;
            _scannerConfigService = scannerConfigService;
            _plcConfigService = plcConfigService;
            _commAddressService = commAddressService;
            _logger = logger;
            _hubContext = hubContext;
        }

        public void Start()
        {
            string ip = ToolsHelper.GetLocalIp().ToString();
            if (string.IsNullOrEmpty(ip))
            {
                _logger.LogWarning("服务器IP获取失败！");
                return;
            }
            ServerConfig hmiConfig = _serverConfigService.QueryByIp(ip);
            if (hmiConfig == null)
            {
                _logger.LogWarning($"无法根据IP查询HMI配置,当前ip:{ip}");
                return;
            }
            List<WorkstationConfig> stationConfigList = _workstationConfigService.QueryByHmiCode(hmiConfig.HmiCode);
            if (stationConfigList.Count.Equals(0))
            {
                _logger.LogWarning("HMI配置下的工站为空");
                return;
            }
            SetScannerConfigurations(stationConfigList);
            CurrentOPInfo.Current.IndustrialComputerConfig = hmiConfig;
            CurrentOPInfo.Current.WorkStationConfig = stationConfigList;
            ConfigurePlcAndScannerCommunications(stationConfigList);
            if (CurrentAppInfo.Current.communicationPairs.Any())
            {
                //PLC连接成功后，定时读取点位信息
                SetupCommunicationWatchdog();
            }
        }

        private void SetScannerConfigurations(List<WorkstationConfig> stationConfigList)
        {
            var workCodeArray = stationConfigList
                .Where(f => f.ScannerEnabled.Equals(1))
                .Select(s => s.WorkstationCode)
                .ToArray();

            if (workCodeArray.Any())
            {
                var workStationByScan = _scannerConfigService.QueryByStationCode(workCodeArray);
                if (workStationByScan.Any())
                {
                    CurrentOPInfo.Current.ScannerConfig = workStationByScan;
                }
            }
        }
        /// <summary>
        /// 遍历工作站表，IF PLC Enable -> 连接PLC
        /// </summary>
        /// <param name="stationConfigList"></param>
        private void ConfigurePlcAndScannerCommunications(List<WorkstationConfig> stationConfigList)
        {
            foreach (var workstationConfigInfo in stationConfigList)
            {
                if (workstationConfigInfo.PlcEnabled.Equals(1))
                {
                    ConfigurePlcCommunication(workstationConfigInfo);
                }
                if (workstationConfigInfo.ScannerEnabled.Equals(1))
                {
                    ConfigureScannerCommunication(workstationConfigInfo);
                }
            }
        }

        /// <summary>
        /// 查询工作站关联的PLC配置 
        /// </summary>
        /// <param name="workstationConfigInfo"></param>
        private void ConfigurePlcCommunication(WorkstationConfig workstationConfigInfo)
        {
            try
            {
                PlcConfig plcConfigInfo = _plcConfigService.QueryInfoByLineAndStation(workstationConfigInfo.ProductionLineCode, workstationConfigInfo.WorkstationCode);
                if (plcConfigInfo == null)
                {
                    _logger.LogWarning($"无法获取PLC配置：{workstationConfigInfo.WorkstationCode}");
                    return;
                }
                INormCommunication comm = new SieminCommunication();
                comm.Connection(plcConfigInfo.PlcAddress, 102, (int)plcConfigInfo.RackNumber, (int)plcConfigInfo.SlotNumber, CpuType.S71200);
               
                //查询配置的指令集 
                var commAddressByDb = _commAddressService
                                    .QueryByOpAndLine(plcConfigInfo.WorkstationCode, plcConfigInfo.ProductionLineCode).Where(w => w.IsDeleted == false);
                if (!commAddressByDb.Any())
                {
                    return;
                }
                // 地址 - 长度
                Dictionary<int, int> keyValues = new Dictionary<int, int>();
                foreach (var item in commAddressByDb.DistinctBy(d => d.BlockAddress))
                {
                    keyValues.Add(item.BlockAddress, item.BlockLength);
                }
                List<CommPoint> commAddress = commAddressByDb
                                    .Select(ca => new CommPoint()
                                    {
                                        ItemNo = ca.ItemNo,
                                        ItemAddress = ca.ItemAddress,
                                        ItemType = ca.ItemDataType,
                                        SubItem = ca.SubscribeState,
                                        BlockAddress = ca.BlockAddress,
                                        BlockLength = ca.BlockLength
                                    }).ToList();
                comm.ConnectionSubPonit(commAddress, keyValues);
                if (comm.Start())
                {
                    Log.WriteLine(ConsoleColor.DarkGreen, $"工位：【{workstationConfigInfo.WorkstationCode}】PLC连接成功！");
                    CurrentAppInfo.Current.communicationPairs.TryAdd(plcConfigInfo.WorkstationCode, comm);
                }
                else
                {
                    Log.WriteLine(ConsoleColor.Red, $"工位：【{workstationConfigInfo.WorkstationCode}】PLC连接失败！");
                }
            }
            catch
            {
                Log.WriteLine(ConsoleColor.Red, $"工位：【{workstationConfigInfo.WorkstationCode}】PLC连接失败！");
            }
        }

        private void ConfigureScannerCommunication(WorkstationConfig workstationConfigInfo)
        {
            try
            {
                IScannCode interfaceEvent = new HandScanCode(workstationConfigInfo.WorkstationCode);
                CurrentAppInfo.Current.IScanCodeInterface.TryAdd(workstationConfigInfo.WorkstationCode, interfaceEvent);
            }
            catch
            {
                _logger.LogWarning($"扫码枪连接失败：{workstationConfigInfo.WorkstationCode}");
            }
        }

        private void SetupCommunicationWatchdog()
        {
            ICommPlcExtend interfaceCommExtend = new CommPlcExtend();
            interfaceCommExtend.Initialize();
            CurrentAppInfo.Current.InterfaceCommExtend = interfaceCommExtend;
            CurrentAppInfo.Current.InterfaceCommExtend.CommunicationDataCallback += InterfaceCommExtend_CommunicationDataCallback;
            DynamicCallExecuteImport();
            watchDogTimer = new System.Timers.Timer();
            watchDogTimer.Elapsed += WatchDog_Elapsed;
            watchDogTimer.Interval = 1000;
            watchDogTimer.AutoReset = true;
            watchDogTimer.Start();
        }

        private void DynamicCallExecuteImport()
        {
            foreach (var executeWork in _executeWorks)
            {
                Task.Run(() =>
                {
                    executeWork.ExecuteImport();
                });
            }
        }

        private void InterfaceCommExtend_CommunicationDataCallback(string stationCode, INormCommunication currentComm, int itemNo, string itemAddress, object itemValue)
        {
            Console.WriteLine($"工位：【{stationCode}】-- 序号：【{itemNo}】-- 地址：【{itemAddress}】-- 数值：【{itemValue}】--时间：【{DateTime.Now.ToString("HH:mm:ss:fff")}】");
        }

        private void WatchDog_Elapsed(object? sender, ElapsedEventArgs e)
        {
            try
            {
                lock (this)
                {
                    foreach (var pair in CurrentAppInfo.Current.communicationPairs)
                    {
                        Int16 valueToWrite = (short)(DateTime.Now.Second % 2);
                        pair.Value.WriteValue(2, valueToWrite);
                        _hubContext.Clients.All.SendAsync($"{pair.Key}WatchDog", valueToWrite);
                    }
                }
            }
            catch { }
        }
    }
}